package com.minelx.scriptbuilder.script.attribute.value;

import com.minelx.scriptbuilder.script.IVariable;

import java.util.Stack;

import static com.minelx.scriptbuilder.script.attribute.value.Operators.*;

public class ArithmeticSequence {

	private final Stack<Operators> operators;

	private final Stack<IVariable> values;

	public ArithmeticSequence(IVariable initValue) {
		operators = new Stack<>();
		values = new Stack<>();
		values.push(initValue);
	}

	public ArithmeticSequence plus(IVariable value) {
		return operateWith(PLUS, value);
	}

	public ArithmeticSequence reduce(IVariable value) {
		return operateWith(REDUCE, value);
	}

	public ArithmeticSequence multi(IVariable value) {
		return operateWith(MULTI, value);
	}

	public ArithmeticSequence operateWith(Operators operator, IVariable value) {
		if (operator.lowOrEquals(prevPushedOperator())) {
			zipValues();
		}
		// add operator and value
		operators.add(operator);
		values.add(value);
		return this;
	}

	public void operateWith(Pair pair) {
		operateWith(pair.getOperator(), pair.getVariable());
	}

	private Operators prevPushedOperator() {
		if (operators.isEmpty()) {
			return UNKNOWN;
		}
		return operators.peek();
	}

	public IVariable pop() {
		IVariable firstPopped = values.pop();
		IVariable secondPopped = values.pop();
		IVariable result = operators.pop().calculate(secondPopped, firstPopped);
		return values.push(result);
	}

	public IVariable toValue() {
		zipValues();
		return values.peek();
	}

	public void zipValues() {
		while (!operators.isEmpty()) {
			pop();
		}
	}

	public static class Pair {
		private final Operators operator;

		private final IVariable variable;

		public Pair(Operators operator, IVariable variable) {
			this.operator = operator;
			this.variable = variable;
		}

		public Operators getOperator() {
			return operator;
		}

		public IVariable getVariable() {
			return variable;
		}

		@Override
		public String toString() {
			return "Pair(" + getOperator() + ", " + getVariable() + ")";
		}
	}
}
